﻿using System;
using System.Net;
using System.Xml.Linq;
using BSDS.Core.Data.Local;
using BSDS.Core.Data.Local.Xml.Parsing;
using BSDS.Core.Data.Remote.Download;
using BSDS.Core.Infrastructure.Configuration;
using BSDS.Core.Infrastructure.Logging;
using BSDS.Core.Infrastructure.RemoteCommunication;
using BSDS.Core.Model.Data;
using BSDS.Core.Model.Services.Jobs;
using BSDS.Core.Model.Services.Jobs.Core;

namespace BSDS.Core.Model.Services
{
    public class DownloadService : IJobStateProvider
    {
        private const string ScheduleDownloadTemplate =
           "https://spatial.virtualearth.net/REST/v1/Dataflows/DataSourceDownload/{0}/{1}?output=xml&key={2}";

        private const string GetStatusQueryTemplate =
            "https://spatial.virtualearth.net/REST/v1/dataflows/DataSourceDownload/{0}?output=xml&key={1}";

        private const string DownloadDataTemplate =
            "https://spatial.virtualearth.net/REST/v1/dataflows/DataSourceDownload/{0}/output/succeeded?key={1}";

        private readonly AccountService accountService;
        private readonly ServiceClient serviceClient;
        private readonly JobRepository jobRepository;
        private readonly DownloadResponseParser requestParser;
        private readonly XmlFormatParser dataParser;
        private readonly Logger logger;
        private readonly IBingKey bingKey;

        public DownloadService(AccountService accountService, ServiceClient serviceClient, JobRepository jobRepository,
            DownloadResponseParser requestParser, XmlFormatParser dataParser,  Logger logger, IBingKey bingKey)
        {
            this.accountService = accountService;
            this.serviceClient = serviceClient;
            this.jobRepository = jobRepository;
            this.requestParser = requestParser;
            this.dataParser = dataParser;
            this.logger = logger;
            this.bingKey = bingKey;
        }

        public DownloadJob ScheduleDownload(string dataSourceName, DataFormat format, string outFile, bool portal)
        {
            var dataSourceInfo = accountService.GetDataSourceInformation(dataSourceName);

            var uri = string.Format(ScheduleDownloadTemplate, dataSourceInfo.AccessId, dataSourceName, bingKey.Value);

            var response = serviceClient.SendRequest(uri, "GET");

            if (response.Status != HttpStatusCode.Created)
            {
                logger.Log("Error scheduling data download.", response);

                throw new Exception(string.Format("Cannot schedule data download.\n{0}", response.Status));
            }

            var job = requestParser.ParseCreateUploadJobResponse(response.Content);
            job.DataSourceName = dataSourceName;
            job.Format = format;
            job.OutFile = outFile;
            job.Portal = portal;

            jobRepository.Save(job);

            return job;
        }

        public JobState QueryState(string jobId)
        {
            var uri = string.Format(GetStatusQueryTemplate, jobId, bingKey);

            var response = serviceClient.SendRequest(uri, "GET");

            return requestParser.ParseGetStatusResponse(jobId, response.Content);

        }

        public BsdsData DownloadResults(DownloadJob job)
        {
            logger.Log("Downloading data for job " + job.Id + ". ");

            var uri = string.Format(DownloadDataTemplate, job.Id, bingKey);

            var response = serviceClient.SendRequest(uri, "GET");

            var data = dataParser.Parse(XDocument.Parse(response.Content));

            return data;
        }
    }
}